#pragma once
#include<iostream>
#include<pthread.h>
#include<queue>
#include<unistd.h>

const int gDefualtcap=5;

template<class T>
class BlockQueue{
private:
    bool isQueueFull()
    {
        return bq_.size()==capacity_;
    }
    bool isQueueEmpty()
    {
        return bq_.size()==0;
    }
    
public:
    BlockQueue(int capacity=gDefualtcap)
    :capacity_(capacity)
    {
        pthread_mutex_init(&pmtx_,nullptr);
        pthread_cond_init(&Full_,nullptr);
        pthread_cond_init(&Empty_,nullptr);
    }
    ~BlockQueue()
    {
        pthread_mutex_destroy(&pmtx_);
        pthread_cond_destroy(&Full_);
        pthread_cond_destroy(&Empty_);
    }

    void push(T &in)
    {
        pthread_mutex_lock(&pmtx_);//加锁
        while(isQueueFull()) pthread_cond_wait(&Full_,&pmtx_);//阻塞等待，调用成功自动释放锁，唤醒自动加锁
        bq_.push(in);
        pthread_cond_signal(&Empty_);
        pthread_mutex_unlock(&pmtx_);//解锁
    }

    void pop(T* out)
    {
        pthread_mutex_lock(&pmtx_);//加锁
        while(isQueueEmpty()) pthread_cond_wait(&Empty_,&pmtx_);//阻塞等待，调用成功自动释放锁，唤醒自动加锁
        *out=bq_.front();
        bq_.pop();
        pthread_cond_signal(&Full_);
        pthread_mutex_unlock(&pmtx_);//解锁
    }
private:
    int capacity_;          //阻塞队列容量上限
    std::queue<T>bq_;             //阻塞队列
    pthread_mutex_t pmtx_;  //互斥锁
    pthread_cond_t Full_;   //条件变量
    pthread_cond_t Empty_;  //条件变量    
};